﻿using System.Collections.Generic;
using Rubikev.Common;

namespace Rubikev.Rockface.Core.Entities
{
   /// <summary>
   /// Represents a place
   /// </summary>
   public class Region : EntityBase, IChildEntity<Region>
   {
      /// <summary>
      /// The maximum number of characters in the name field
      /// </summary>
      public const int MaxNameLength = 255;

      public Region()
      {
         childRegions = new List<Region>();
         climbs = new List<Climb>();
      }

      #region Properties

      /// <summary>
      /// The parent of this region, e.g. the parent of 'Kent' would be 'England'
      /// </summary>
      public virtual Region ParentEntity { get; set; }

      /// <summary>
      /// The latitude of the region's location
      /// </summary>
      public virtual double Latitude { get; set; }

      /// <summary>
      /// The longitude of the region's location
      /// </summary>
      public virtual double Longitude { get; set; }

      private IList<Region> childRegions;

      /// <summary>
      /// The direct child regions for this region, e.g. the children of 'Kent' would be 'Maidstone', 'Sheerness', etc.
      /// </summary>
      public virtual IEnumerable<Region> ChildRegions
      {
         get { return childRegions; }
         set { childRegions = (IList<Region>)value; }
      }

      private IList<Climb> climbs;

      /// <summary>
      /// The climbs within only this region, i.e. excluding the ones in the child regions
      /// </summary>
      public virtual IEnumerable<Climb> Climbs
      {
         get { return climbs; }
         set { climbs = (IList<Climb>)value; }
      }

      /// <summary>
      /// The type of this region, e.g. 'Country', 'Town', etc.
      /// </summary>
      public virtual RegionType Type { get; set; }

      /// <summary>
      /// The name of the region
      /// </summary>
      public virtual string Name { get; set; }

      #endregion


      #region Bi-directional Collection Methods

      /// <summary>
      /// Adds the region to the <see cref="ChildRegions"/> collection
      /// </summary>
      /// <param name="childRegion">The region to add</param>
      public virtual void AddChildRegion(Region childRegion)
      {
         AddEntityToBiDirectionalCollection(childRegions, childRegion, this);
      }

      /// <summary>
      /// Adds the climb to the <see cref="Climbs"/> collection
      /// </summary>
      /// <param name="climb">The climb to add</param>
      public virtual void AddClimb(Climb climb)
      {
         AddEntityToBiDirectionalCollection(climbs, climb, this);
      }

      /// <summary>
      /// Removes the child region from this region
      /// </summary>
      /// <param name="childRegion">The region to remove</param>
      public virtual void RemoveChildRegion(Region childRegion)
      {
         RemoveEntityFromBiDirectionalCollection<Region, Region>(childRegions, childRegion);
      }

      /// <summary>
      /// Removes all child regions from this region
      /// </summary>
      public virtual void ClearChildRegions()
      {
         ClearBiDirectionalAssociation<Region, Region>(childRegions);
      }

      /// <summary>
      /// Removes the climb from this region
      /// </summary>
      /// <param name="climb">The climb to remove</param>
      public virtual void RemoveClimb(Climb climb)
      {
         RemoveEntityFromBiDirectionalCollection<Climb, Region>(climbs, climb);
      }

      /// <summary>
      /// Removes all climbs from this region
      /// </summary>
      public virtual void ClearClimbs()
      {
         ClearBiDirectionalAssociation<Climb, Region>(climbs);
      }

      #endregion
   }
}
